// knowledgeTreeController.js - 知识树控制器1
const KnowledgeNode = require('../models/knowledgeNode');
const asyncHandler = require('express-async-handler');
const mongoose = require('mongoose');

/**
 * @swagger
 * /api/knowledge-tree:
 *   get:
 *     summary: 获取整棵知识树
 *     description: 检索完整的知识树结构
 *     tags: [KnowledgeTree]
 *     responses:
 *       200:
 *         description: 成功获取知识树
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 success:
 *                   type: boolean
 *                 data:
 *                   type: array
 *                   items:
 *                     $ref: '#/components/schemas/KnowledgeNode'
 *               example:
 *                 success: true
 *                 data:
 *                   - id: "60f3b1a7e6b3a40015f3d8a1"
 *                     title: "根节点"
 *                     content: "根节点内容"
 *                     parentId: null
 *                     order: 0
 *                     level: 0
 *                     createdBy: "60f3b1a7e6b3a40015f3d8a2"
 *                     children: []
 *                     createdAt: "2023-07-18T12:34:56.789Z"
 *                     updatedAt: "2023-07-18T12:34:56.789Z"
 *       500:
 *         description: 服务器错误
 */
exports.getTree = asyncHandler(async (req, res) => {
  // 使用模型中定义的静态方法获取整棵树
  const tree = await KnowledgeNode.getTree();
  
  res.status(200).json({
    success: true,
    data: tree
  });
});

/**
 * @swagger
 * /api/knowledge-tree/{nodeId}:
 *   get:
 *     summary: 获取节点详情
 *     description: 获取单个节点及其子节点信息
 *     tags: [KnowledgeTree]
 *     parameters:
 *       - in: path
 *         name: nodeId
 *         required: true
 *         schema:
 *           type: string
 *         description: 节点ID
 *     responses:
 *       200:
 *         description: 成功获取节点
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 success:
 *                   type: boolean
 *                 data:
 *                   $ref: '#/components/schemas/KnowledgeNode'
 *               example:
 *                 success: true
 *                 data:
 *                   id: "60f3b1a7e6b3a40015f3d8a1"
 *                   title: "数学基础"
 *                   content: "包括算术和代数基础"
 *                   parentId: "60f3b1a7e6b3a40015f3d8a0"
 *                   order: 0
 *                   level: 1
 *                   createdBy: "60f3b1a7e6b3a40015f3d8a2"
 *                   children:
 *                     - id: "60f3b1a7e6b3a40015f3d8a3"
 *                       title: "算术"
 *                       content: "加减乘除运算"
 *                       parentId: "60f3b1a7e6b3a40015f3d8a1"
 *                       order: 0
 *                       level: 2
 *                       createdBy: "60f3b1a7e6b3a40015f3d8a2"
 *                       children: []
 *                       createdAt: "2023-07-18T12:34:56.789Z"
 *                       updatedAt: "2023-07-18T12:34:56.789Z"
 *                   createdAt: "2023-07-18T12:34:56.789Z"
 *                   updatedAt: "2023-07-18T12:34:56.789Z"
 *       400:
 *         description: 无效的节点ID格式
 *       404:
 *         description: 节点不存在
 *       500:
 *         description: 服务器错误
 */
exports.getNode = asyncHandler(async (req, res) => {
  const { nodeId } = req.params;
  
  // 验证节点ID格式
  if (!mongoose.Types.ObjectId.isValid(nodeId)) {
    res.status(400);
    throw new Error('无效的节点ID格式');
  }
  
  // 使用模型中定义的静态方法获取节点及其子节点
  const node = await KnowledgeNode.getNodeWithChildren(nodeId);
  
  if (!node) {
    res.status(404);
    throw new Error('节点不存在');
  }
  
  res.status(200).json({
    success: true,
    data: node
  });
});

/**
 * @swagger
 * /api/knowledge-tree:
 *   post:
 *     summary: 创建新节点
 *     description: 在知识树中创建新节点
 *     tags: [KnowledgeTree]
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required: [title]
 *             properties:
 *               title:
 *                 type: string
 *               content:
 *                 type: string
 *               parentId:
 *                 type: string
 *               order:
 *                 type: number
 *     responses:
 *       201:
 *         description: 节点创建成功
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 success:
 *                   type: boolean
 *                 message:
 *                   type: string
 *                 data:
 *                   $ref: '#/components/schemas/KnowledgeNode'
 *               example:
 *                 success: true
 *                 message: "节点创建成功"
 *                 data:
 *                   id: "60f3b1a7e6b3a40015f3d8a4"
 *                   title: "新节点"
 *                   content: "节点内容"
 *                   parentId: "60f3b1a7e6b3a40015f3d8a1"
 *                   order: 1
 *                   level: 2
 *                   createdBy: "60f3b1a7e6b3a40015f3d8a2"
 *                   children: []
 *                   createdAt: "2023-07-18T12:35:56.789Z"
 *                   updatedAt: "2023-07-18T12:35:56.789Z"
 *       400:
 *         description: 节点标题不能为空或无效的父节点ID
 *       404:
 *         description: 父节点不存在
 *       500:
 *         description: 创建节点失败
 */
exports.createNode = asyncHandler(async (req, res) => {
  const { title, content, parentId, order } = req.body;
  
  // 验证必要字段
  if (!title) {
    res.status(400);
    throw new Error('节点标题不能为空');
  }
  
  // 创建节点数据对象
  const nodeData = { title, content };
  
  // 如果提供了parentId，需要检查父节点是否存在
  if (parentId) {
    // 验证parentId格式
    if (!mongoose.Types.ObjectId.isValid(parentId)) {
      res.status(400);
      throw new Error('无效的父节点ID格式');
    }
    
    const parentNode = await KnowledgeNode.findById(parentId);
    
    if (!parentNode) {
      res.status(404);
      throw new Error('父节点不存在');
    }
    
    // 设置父节点ID和层级
    nodeData.parentId = parentId;
    nodeData.level = parentNode.level + 1;
  } else {
    // 没有父节点，则为根节点，层级为0
    nodeData.level = 0;
  }
  
  // 设置排序序号
  if (order !== undefined) {
    nodeData.order = order;
  } else {
    // 默认添加到同级节点最后
    const lastNode = await KnowledgeNode.findOne(
      { parentId: nodeData.parentId || null }
    ).sort({ order: -1 });
    
    nodeData.order = lastNode ? lastNode.order + 1 : 0;
  }
  
  // 创建新节点
  const newNode = new KnowledgeNode(nodeData);
  await newNode.save();
  
  res.status(201).json({
    success: true,
    message: '节点创建成功',
    data: newNode
  });
});

/**
 * @swagger
 * /api/knowledge-tree/{nodeId}:
 *   put:
 *     summary: 更新节点信息
 *     description: 更新指定节点的元数据
 *     tags: [KnowledgeTree]
 *     parameters:
 *       - in: path
 *         name: nodeId
 *         required: true
 *         schema:
 *           type: string
 *         description: 要更新的节点ID
 *     requestBody:
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             properties:
 *               title:
 *                 type: string
 *               content:
 *                 type: string
 *               order:
 *                 type: number
 *     responses:
 *       200:
 *         description: 节点更新成功
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 success:
 *                   type: boolean
 *                 message:
 *                   type: string
 *                 data:
 *                   $ref: '#/components/schemas/KnowledgeNode'
 *               example:
 *                 success: true
 *                 message: "节点更新成功"
 *                 data:
 *                   id: "60f3b1a7e6b3a40015f3d8a1"
 *                   title: "更新后的节点"
 *                   content: "更新后的内容"
 *                   parentId: "60f3b1a7e6b3a40015f3d8a0"
 *                   order: 2
 *                   level: 1
 *                   createdBy: "60f3b1a7e6b3a40015f3d8a2"
 *                   children: []
 *                   createdAt: "2023-07-18T12:34:56.789Z"
 *                   updatedAt: "2023-07-18T12:38:56.789Z"
 *       400:
 *         description: 无效的节点ID格式
 *       404:
 *         description: 节点不存在
 *       500:
 *         description: 更新节点失败
 */
exports.updateNode = asyncHandler(async (req, res) => {
  const { nodeId } = req.params;
  const { title, content, order } = req.body;
  
  // 验证节点ID格式
  if (!mongoose.Types.ObjectId.isValid(nodeId)) {
    res.status(400);
    throw new Error('无效的节点ID格式');
  }
  
  // 查找节点
  const node = await KnowledgeNode.findById(nodeId);
  
  if (!node) {
    res.status(404);
    throw new Error('节点不存在');
  }
  
  // 更新字段
  if (title !== undefined) node.title = title;
  if (content !== undefined) node.content = content;
  if (order !== undefined) node.order = order;
  
  // 保存更新
  await node.save();
  
  res.status(200).json({
    success: true,
    message: '节点更新成功',
    data: node
  });
});

/**
 * @swagger
 * /api/knowledge-tree/{nodeId}/move:
 *   patch:
 *     summary: 移动节点
 *     description: 修改节点的父节点或排序顺序
 *     tags: [KnowledgeTree]
 *     parameters:
 *       - in: path
 *         name: nodeId
 *         required: true
 *         schema:
 *           type: string
 *         description: 要移动的节点ID
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required: [dropNodeId, dropType]
 *             properties:
 *               dropNodeId:
 *                 type: string
 *                 description: 目标节点ID
 *               dropType:
 *                 type: string
 *                 enum: [inner, before, after]
 *                 description: 放置类型(inner-作为子节点/before-之前/after-之后)
 *     responses:
 *       200:
 *         description: 节点移动成功
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 success:
 *                   type: boolean
 *                 message:
 *                   type: string
 *                 data:
 *                   $ref: '#/components/schemas/KnowledgeNode'
 *               example:
 *                 success: true
 *                 message: "节点移动成功"
 *                 data:
 *                   id: "60f3b1a7e6b3a40015f3d8a1"
 *                   title: "移动后的节点"
 *                   content: "节点内容"
 *                   parentId: "60f3b1a7e6b3a40015f3d8a5"
 *                   order: 1.5
 *                   level: 2
 *                   createdBy: "60f3b1a7e6b3a40015f3d8a2"
 *                   children: []
 *                   createdAt: "2023-07-18T12:34:56.789Z"
 *                   updatedAt: "2023-07-18T12:45:56.789Z"
 *       400:
 *         description: 无效参数或循环引用
 *       404:
 *         description: 节点不存在
 *       500:
 *         description: 移动节点失败
 */
exports.moveNode = asyncHandler(async (req, res) => {
  const { nodeId } = req.params; // 要移动的节点ID
  const { dropNodeId, dropType } = req.body; // 目标节点ID和放置类型
  
  // 验证节点ID格式
  if (!mongoose.Types.ObjectId.isValid(nodeId)) {
    res.status(400);
    throw new Error('无效的节点ID格式');
  }
  
  // 查找要移动的节点
  const node = await KnowledgeNode.findById(nodeId);
  if (!node) {
    res.status(404);
    throw new Error('节点不存在');
  }

  // 处理放置到根节点的情况
  let parentId = null;
  
  if (dropNodeId) {
    // 验证目标节点ID格式
    if (!mongoose.Types.ObjectId.isValid(dropNodeId)) {
      res.status(400);
      throw new Error('无效的目标节点ID格式');
    }

    // 查找目标节点
    const dropNode = await KnowledgeNode.findById(dropNodeId);
    if (!dropNode) {
      res.status(404);
      throw new Error('目标节点不存在');
    }

    // 防止循环引用
    const descendants = await getDescendants(nodeId);
    if (descendants.includes(dropNodeId)) {
      res.status(400);
      throw new Error('无法将节点移动到其子节点下');
    }

    // 根据dropType设置parentId和order
    if (dropType === 'inner') {
      // 作为子节点插入
      parentId = dropNodeId;
      // 获取目标节点的最后一个子节点
      const lastChild = await KnowledgeNode.findOne({ parentId: dropNodeId })
        .sort({ order: -1 })
        .limit(1);
      node.order = lastChild ? lastChild.order + 1 : 1;
    } else {
      // 作为兄弟节点插入
      parentId = dropNode.parentId || null;
      
      // 获取同级节点
      const siblings = await KnowledgeNode.find({ 
        parentId: parentId || null 
      }).sort({ order: 1 });
      const refIndex = siblings.findIndex(n => n.id === dropNodeId);
      if (refIndex === -1) {
        res.status(400);
        throw new Error('参考节点不在同级节点中');
      }

      // 计算新order值
      if (dropType === 'before') {
        // 插入到参考节点前面
        const prevNode = refIndex > 0 ? siblings[refIndex - 1] : null;
        const refNode = siblings[refIndex];
        node.order = prevNode ? 
          (prevNode.order + refNode.order) / 2 : 
          refNode.order - 1;
      } else {
        // 插入到参考节点后面
        const nextNode = refIndex < siblings.length - 1 ? siblings[refIndex + 1] : null;
        const refNode = siblings[refIndex];
        node.order = nextNode ? 
          (refNode.order + nextNode.order) / 2 : 
          refNode.order + 1;
      }
    }
  } else {
    // 放置到根节点
    node.order = 1;
  }

  // 更新节点信息
  if (parentId !== null) {
    const parentNode = await KnowledgeNode.findById(parentId);
    node.parentId = parentId;
    node.level = parentNode ? parentNode.level + 1 : 0;
  } else {
    node.parentId = null;
    node.level = 0;
  }

  // 保存节点
  await node.save();
  
  // 更新子节点的level
  await node.updateChildrenLevel();
  
  // 保存更新
  // await node.save();
  
  res.status(200).json({
    success: true,
    message: '节点移动成功',
    data: node
  });
});

/**
 * @swagger
 * /api/knowledge-tree/{nodeId}:
 *   delete:
 *     summary: 删除节点
 *     description: 删除指定节点及其子节点
 *     tags: [KnowledgeTree]
 *     parameters:
 *       - in: path
 *         name: nodeId
 *         required: true
 *         schema:
 *           type: string
 *         description: 要删除的节点ID
 *     responses:
 *       200:
 *         description: 节点删除成功
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 success:
 *                   type: boolean
 *                 message:
 *                   type: string
 *               example:
 *                 success: true
 *                 message: "节点删除成功"
 *       400:
 *         description: 无效的节点ID格式
 *       404:
 *         description: 节点不存在
 *       500:
 *         description: 删除节点失败
 */
exports.deleteNode = asyncHandler(async (req, res) => {
  const { nodeId } = req.params;
  
  // 验证节点ID格式
  if (!mongoose.Types.ObjectId.isValid(nodeId)) {
    res.status(400);
    throw new Error('无效的节点ID格式');
  }
  
  // 查找节点
  const node = await KnowledgeNode.findById(nodeId);
  
  if (!node) {
    res.status(404);
    throw new Error('节点不存在');
  }
  
  // 获取父节点ID（可能为null）
  const parentId = node.parentId;
  
  // 查找所有子节点
  const childNodes = await KnowledgeNode.find({ parentId: nodeId });
  
  // 将子节点上移到该节点的父节点下
  const updatePromises = childNodes.map(async (childNode) => {
    childNode.parentId = parentId;
    
    // 如果父节点存在，更新level
    if (parentId) {
      const parentNode = await KnowledgeNode.findById(parentId);
      childNode.level = parentNode.level + 1;
    } else {
      childNode.level = 0; // 根节点
    }
    
    return childNode.save();
  });
  
  // 等待所有子节点更新完成
  await Promise.all(updatePromises);
  
  // 删除节点
  await KnowledgeNode.findByIdAndDelete(nodeId);
  
  res.status(200).json({
    success: true,
    message: '节点删除成功'
  });
});

// 辅助函数：将同级节点的order值规范化为整数序列
async function normalizeOrders(nodes) {
  const updateOps = nodes.map((node, index) => {
    node.order = index;
    return node.save();
  });
  await Promise.all(updateOps);
}

// 辅助函数：获取节点的所有后代节点ID
async function getDescendants(nodeId) {
  // 查找所有直接子节点
  const children = await KnowledgeNode.find({ parentId: nodeId });
  
  let descendants = children.map(child => child.id);
  
  // 递归获取每个子节点的后代
  for (const child of children) {
    const childDescendants = await getDescendants(child.id);
    descendants = descendants.concat(childDescendants);
  }
  
  return descendants;
}
